package com.itcms.core.security;

import java.io.Serializable;
import java.util.Deque;
import java.util.LinkedList;

import javax.annotation.Resource;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;

import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.session.Session;
import org.apache.shiro.session.mgt.DefaultSessionKey;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.web.filter.AccessControlFilter;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.apache.shiro.web.util.WebUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;

/**
 * 
 * @Title: KickoutSessionControlFilter.java
 * @Package com.agood.bejavagod.controller.filter
 * @Description: 同一用户后登陆踢出前面的用户 Copyright: Copyright (c) 2016
 *               Company:Nathan.Lee.Salvatore
 * 
 * @author mengjie
 * @date 2016年12月12日 下午7:25:40
 * @version V1.0
 */
public class KickoutSessionControlFilter extends AccessControlFilter {

	private String kickoutUrl; // 踢出后到的地址
	private boolean kickoutAfter = false; // 踢出之前登录的/之后登录的用户 默认踢出之前登录的用户
	private int maxSession = 1; // 同一个帐号最大会话数 默认1

	private Cache<String, Deque<Session>> cacheSession;

	public void setKickoutUrl(String kickoutUrl) {
		this.kickoutUrl = kickoutUrl;
	}

	public void setKickoutAfter(boolean kickoutAfter) {
		this.kickoutAfter = kickoutAfter;
	}

	public void setMaxSession(int maxSession) {
		this.maxSession = maxSession;
	}

	public void setCacheManager(CacheManager cacheManager) {
		this.cacheSession = cacheManager.getCache("shiro-kickout-session");
	}

	@Override
	protected boolean isAccessAllowed(ServletRequest request,
			ServletResponse response, Object mappedValue) throws Exception {
		return false;
	}

	@Override
	protected boolean onAccessDenied(ServletRequest request,
			ServletResponse response) throws Exception {
		/*
		 * if(!"true".equals(kickout)){ //如果不需要单用户登录的限制 return true; }
		 */
		Subject subject = getSubject(request, response);
		if (!subject.isAuthenticated() && !subject.isRemembered()) {
			// 如果没有登录，直接进行之后的流程
			return true;
		}

		Session session = subject.getSession();
		String username = (String) subject.getPrincipal().toString();
		Serializable sessionId = session.getId();

		Deque<Session> dequeSession = cacheSession.get(username);
		if (dequeSession == null) {
			dequeSession = new LinkedList<Session>();
			cacheSession.put(username, dequeSession);
		}

		// 如果队列里没有此sessionId，且用户没有被踢出；放入队列
		boolean whetherPutDeQue = true;
		if (dequeSession.isEmpty()) {
			whetherPutDeQue = true;
		} else {
			for (Session sessionInqueue : dequeSession) {
				if (sessionId.equals(sessionInqueue.getId())) {
					whetherPutDeQue = false;
					break;
				}
			}
		}
		if (whetherPutDeQue) {
			dequeSession.push(session);
		}

		// 如果队列里的sessionId数超出最大会话数，开始踢人
		while (dequeSession.size() > maxSession) {
			Session kickoutSession = null;
			if (kickoutAfter) { // 如果踢出后者
				kickoutSession = dequeSession.removeFirst();
				System.out.println("踢出后登录的，被踢出的sessionId为: "
						+ kickoutSession.getId());
			} else { // 否则踢出前者
				kickoutSession = dequeSession.removeLast();
				System.out.println("踢出先登录的，被踢出的sessionId为: "
						+ kickoutSession.getId());
			}
			try {
				if (kickoutSession != null) {
					// 设置会话的kickout属性表示踢出了
					// kickoutSession.setAttribute("kickout", true);
					kickoutSession.stop();
					try {
						subject.logout();
					} catch (Exception e) { // ignore
					}
					saveRequest(request);
					WebUtils.issueRedirect(request, response, kickoutUrl);
					return false;
				}
			} catch (Exception e) {// ignore exception
			}
		}

		// 如果被踢出了，直接退出，重定向到踢出后的地址
		/*
		 * if (session != null && session.getAttribute("kickout") != null) {
		 * //会话被踢出了 try { subject.logout(); } catch (Exception e) { //ignore }
		 * saveRequest(request); WebUtils.issueRedirect(request, response,
		 * kickoutUrl); return false; }
		 */

		return true;
	}
}